using System.Collections;
using System.Collections.Generic;
using Google.Protobuf;
using System;
using UnityEngine;
using Cysharp.Threading.Tasks;
using System.Reflection;

public class NetMgr : Singleton<NetMgr>
{
    // receive protocol callback dic
    Dictionary<int,Action<byte[],int>> protocol_dic = new Dictionary<int,Action<byte[],int>>();
    //freeze protocol dic
    Dictionary<int,bool> freeze_protocol_dic = new Dictionary<int,bool>();
    //freeze protocol data Queue
    Dictionary<int,Queue<byte[]>> freeze_protocol_data_dic = new Dictionary<int,Queue<byte[]>>();

    public void RegisterProtocol<T>(int protocol_id,Action<T,int> callback) where T : IMessage<T>
    {
        if(protocol_dic.ContainsKey(protocol_id))
        {
            Debug.LogError("protocol id is already exist");
            return;
        }
        protocol_dic.Add(protocol_id,(data,code) => {
            PropertyInfo propertyInfo = typeof(T).GetProperty("Parser",BindingFlags.Static | BindingFlags.Public);
            MethodInfo methodInfo = propertyInfo.PropertyType.GetMethod("ParseFrom",new Type[]{typeof(byte[])});
            T res = (T)methodInfo.Invoke(propertyInfo.GetValue(null),new object[]{data});
            callback(res,code);
        });
    }

    public void UnRegisterProtocol(int protocol_id)
    {
        if(protocol_dic.ContainsKey(protocol_id))
        {
            protocol_dic.Remove(protocol_id);
        }
    }

    async public UniTask SendProtocol<T>(int protocol_id,T data) where T : IMessage<T>
    {
        byte[] bytes = data.ToByteArray();
        //send protocol
        // httpmgr 
        // await HttpMgr.Instance.HttpPostAsync(protocol_id,bytes);
        // tcpmgr
        await TCPMgr.Instance.Send(protocol_id,bytes);
    }

    public void Dispatch(int protocol_id,byte[] data,int code)
    {
        if(freeze_protocol_dic.ContainsKey(protocol_id))
        {
            if(freeze_protocol_dic[protocol_id])
            {
                if(!freeze_protocol_data_dic.ContainsKey(protocol_id))
                {
                    freeze_protocol_data_dic.Add(protocol_id,new Queue<byte[]>());
                }
                freeze_protocol_data_dic[protocol_id].Enqueue(data);
                return;
            }
        }

        if(protocol_dic.ContainsKey(protocol_id))
        {
            protocol_dic[protocol_id](data,code);
        }
    }

    //freeze protocol
    public void FreezeProtocol(int protocol_id)
    {
        if(!freeze_protocol_dic.ContainsKey(protocol_id))
        {
            freeze_protocol_dic.Add(protocol_id,true);
        }
        else
        {
            freeze_protocol_dic[protocol_id] = true;
        }
    }

    //unfreeze protocol
    public void UnFreezeProtocol(int protocol_id)
    {
        if(!freeze_protocol_dic.ContainsKey(protocol_id))
        {
            freeze_protocol_dic.Add(protocol_id,false);
        }
        else
        {
            freeze_protocol_dic[protocol_id] = false;
        }
        
        if(freeze_protocol_data_dic.ContainsKey(protocol_id))
        {
            while(freeze_protocol_data_dic[protocol_id].Count > 0)
            {
                byte[] data = freeze_protocol_data_dic[protocol_id].Dequeue();
                Dispatch(protocol_id,data,0);
            }
        }
    }
}

